/************C++ Header File****************
#
#	Filename: IOCP.h
#
#	Author: H`W
#	Description: ---
#	Create: 2018-08-11 17:40:43
#	Last Modified: 2018-08-11 17:40:43
*******************************************/
#pragma once

#include "Poller.h"
#include <functional>
#include <atomic>
#include "thread/Sem.h"
#include "thread/Mutex.h"

#if defined _WIN32 && defined IOCP_ENABLE

namespace chaos
{

	const int NOTIFY_SHUTDOWN_KEY = -1;

	typedef std::function<void(OVERLAPPED* o, DWORD bytes, ULONG_PTR lpCompletionKey, bool bOk)> IOCP_CALLBACK;

	typedef struct
	{
		OVERLAPPED overlapped;
		WSABUF wsabufs[MAX_IOVEC];
		socket_t fd;
		IOCP_CALLBACK	cb;
		std::atomic<bool> eventDestroy;
	}COMPLETION_OVERLAPPED, *LPCOMPLETION_OVERLAPPED;


	typedef struct
	{
		COMPLETION_OVERLAPPED overlapped;
		socket_t acceptfd;
		int inListenerPos;				//在listener的ACCEPT_OVERLAPPED数组中的位置
		int* refcnt;					//在listener中投递AcceptEx引用的该结构的个数(listener中的每个ACCEPT_OVERLAPPED此字段都指向同一个数值)
	}ACCEPT_OVERLAPPED, *LPACCEPT_OVERLAPPED;


	class IOCP : public Poller
	{
	public:
		static const int DEFAULT_TIMEOUT = 10000;

		typedef BOOL(WINAPI *AcceptExPtr)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED);
		typedef BOOL(WINAPI *ConnectExPtr)(SOCKET, const struct sockaddr *, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED);
		typedef void (WINAPI *GetAcceptExSockaddrsPtr)(PVOID, DWORD, DWORD, DWORD, LPSOCKADDR *, LPINT, LPSOCKADDR *, LPINT);

		IOCP(EventCentre* pCentre);
		~IOCP();

		virtual int Init();

		virtual int Launch(int timeoutMs, EventList& activeEvents) override;

		static BOOL AcceptEx(SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, DWORD dwReceiveDataLength, 
			DWORD dwLocalAddressLength, DWORD dwRemoteAddressLength, LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped);

		static BOOL ConnectEx(SOCKET s, const struct sockaddr* name, int namelen, PVOID lpSendBuffer, DWORD dwSendDataLength, 
			LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped);

		static void GetAcceptExSockeaddrs(PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, 
			DWORD dwRemoteAddressLength, LPSOCKADDR* LocalSockaddr, LPINT LocalSockaddrLength, LPSOCKADDR * RemoteSockaddr, LPINT RemoteSockaddrLength);

	protected:
		virtual int RegistFd(socket_t fd, short ev) override;

	private:
		static void* GetExtensionFunction(const GUID& funcGUID);

		static unsigned int __stdcall Loop(void* arg);

	private:
		HANDLE m_completionPort;
		bool m_isInit;
		DWORD m_workThreads;				//线程数量
		HANDLE* m_threadHandles;			//所有线程
		thread_t* m_tids;					//所有线程ID
		
		static AcceptExPtr	s_acceptEx;
		static ConnectExPtr s_connectEx;
		static GetAcceptExSockaddrsPtr s_getAcceptExSockaddrs;
	};
}


#endif // _WIN32
